#ifndef __HSM_H__
#define __HSM_H__

#include "SharedPtr.h"

#ifdef HSM_NASSERT          /* HSM_NASSERT defined--assertion checking disabled */

    #define HSM_DEFINE_THIS_FILE
    #define HSM_DEFINE_THIS_MODULE(name_)
    #define HSM_ASSERT(test_)    ((void)0)
    #define HSM_ALLEGE(test_)    ((void)(test_))
    #define HSM_ERROR()          ((void)0)

#else                  /* HSM_NASSERT not defined--assertion checking enabled */

   /** General purpose assertion that makes sure the \a test_ argument is
    * TRUE. Calls the HSM_onAssert() callback if the \a test_ evaluates
    * to FALSE.
    * \note the \a test_ is NOT evaluated if assertions are
    * disabled with the HSM_NASSERT switch.
    */
    #define HSM_ASSERT(test_) ASSERT(test_)

    /** General purpose assertion that ALWAYS evaluates the \a test_
    * argument and calls the HSM_onAssert() callback if the \a test_
    * evaluates to FALSE.
    * \note the \a test_ argument IS always evaluated even when assertions are
    * disabled with the HSM_NASSERT macro. When the HSM_NASSERT macro is
    * defined, the HSM_onAssert() callback is NOT called, even if the
    * \a test_ evaluates to FALSE.
    */
    #define HSM_ALLEGE(test_)    ASSERT(test_)

    /** Assertion that always calls the HSM_onAssert() callback if
    * ever executed.
    * \note can be disabled with the HSM_NASSERT switch.
    */
    #define HSM_ERROR()  ASSERT(false)

#endif                                                         /* HSM_NASSERT */

/** Assertion that checks for a precondition. This macro is equivalent to
* \ref HSM_ASSERT, except the name provides a better documentation of the
* intention of this assertion.
*/
#define HSM_REQUIRE(test_)   ASSERT(test_)

/** Assertion that checks for a postcondition. This macro is equivalent to
* \ref HSM_ASSERT, except the name provides a better documentation of the
* intention of this assertion.
*/
#define HSM_ENSURE(test_)    ASSERT(test_)

/** Assertion that checks for an invariant. This macro is equivalent to
* \ref HSM_ASSERT, except the name provides a better documentation of the
* intention of this assertion.
*/
#define HSM_INVARIANT(test_) ASSERT(test_)

/** Compile-time assertion exploits the fact that in C/C++ a dimension of
* an array cannot be negative. The following declaration causes a compilation
* error if the compile-time expression (\a test_) is not TRUE. The assertion
* has no runtime side effects.
*/
#define HSM_ASSERT_COMPILE(test_) \
    extern char HSM_assert_compile[(test_) ? 1 : -1]

#include <stdint.h>


#define WGS_HSM_STATUS_NAME		hsm_status_mutex
//#define WGS_HSM_STATUS_MUTEX 		mutable boost::recursive_mutex WGS_HSM_STATUS_NAME;
//#define WGS_HSM_STATUS_LOCK         	boost::recursive_mutex::scoped_lock wgsHSMStatusMutexLock(WGS_HSM_STATUS_NAME);
#define WGS_HSM_STATUS_MUTEX 		mutable boost::mutex WGS_HSM_STATUS_NAME;
#define WGS_HSM_STATUS_LOCK         	boost::lock_guard<boost::mutex>  wgsHSMStatusMutexLock(WGS_HSM_STATUS_NAME);


typedef uint16_t HSMSignal;
//////////////////////////////////////////////////////////////////////////////
/// \brief HSMEvent base class.
///
/// HSMEvent represents events without parameters and serves as the base class
/// for derivation of events with parameters.
///
/// \note All data members of the HSMEvent class must remain public to keep it
/// an AGGREGATE. Therefore, the attribute HSMEvent::dynamic_ cannot be
/// declared private.
///
/// The following example illustrates how to add an event parameter by
/// inheriting from the HSMEvent class.
/// \include HSM_HSMEvent.cpp
struct HSMEvent {
    HSMSignal sig;                             ///< signal of the event instance
    uint8 dynamic_;  ///< attributes of a dynamic event (0 for static event)
};

//////////////////////////////////////////////////////////////////////////////

                       /// \brief Type returned from  a state-handler function
typedef uint8 HSMState;

                                  /// \brief pointer to state-handler function
typedef HSMState (*HSMStateHandler)(void *me, HSMEvent const *e);

class Hsm {
protected:
    HSMStateHandler m_state;          ///< current active state (state-variable)

public:
	
    WGS_HSM_STATUS_MUTEX
    /// \brief virtual destructor
    virtual ~Hsm();

    /// \brief Performs the second step of HSM initialization by triggering
    /// the top-most initial transition.
    ///
    /// \param e constant pointer ::HSMEvent or a class derived from ::HSMEvent
    /// \note Must be called only ONCE before Hsm::dispatch()
    ///
    /// The following example illustrates how to initialize a HSM, and
    /// dispatch events to it:
    /// \include HSM_Hsm_use.cpp
    void hsm_init(HSMEvent const *e = (HSMEvent *)0);

    /// \brief Dispatches an event to a HSM
    ///
    /// Processes one event at a time in Run-to-Completion (RTC) fashion.
    /// The argument \a e is a constant pointer the ::HSMEvent or a
    /// class derived from ::HSMEvent.
    ///
    /// \note Must be called after Hsm::init().
    ///
    /// \sa example for Hsm::init()
    void hsm_dispatch(HSMEvent const *e);


    void hsm_transform(HSMStateHandler state);

    /// \brief Tests if a given state is part of the current active state
    /// configuratioin
    ///
    /// \param state is a pointer to the state handler function, e.g.,
    /// &QCalc::on.
    uint8 hsm_isIn(HSMStateHandler state);

protected:

    /// \brief Protected constructor of a HSM.
    ///
    /// Performs the first step of HSM initialization by assigning the
    /// initial pseudostate to the currently active state of the state
    /// machine.
    ///
    /// \note The constructor is protected to prevent direct instantiating
    /// of Hsm objects. This class is intended for subclassing only.
    ///
    /// \sa The ::Hsm example illustrates how to use the Hsm constructor
    /// in the constructor initializer list of the derived state machines.
    /// \sa QFsm::QFsm()
    Hsm(HSMStateHandler initial) : m_state(initial) {}

    /// \brief the top-state.
    ///
    /// Hsm::top() is the ultimate root of state hierarchy in all HSMs
    /// derived from ::Hsm. This state handler always returns (HSMState)0,
    /// which means that it "handles" all events.
    ///
    /// \sa Example of the QCalc::on() state handler.
    static HSMState hsm_top(Hsm *me, HSMEvent const *e);
};

/// \brief Value returned by a non-hierarchical state-handler function when
/// it ignores (does not handle) the event.
#define HSM_RET_IGNORED       ((HSMState)1)

/// \brief The macro returned from a non-hierarchical state-handler function
/// when it ignores (does not handle) the event.
///
/// You call that macro after the return statement (return HSM_IGNORED();)
///
/// \include qepn_qfsm.cpp
#define HSM_IGNORED()         (HSM_RET_IGNORED)

/// \brief Value returned by a state-handler function when it handles
/// the event.
#define HSM_RET_HANDLED       ((HSMState)0)

/// \brief Value returned by a state-handler function when it handles
/// the event.
///
/// You call that macro after the return statement (return HSM_HANDLED();)
/// HSM_HANDLED() can be used both in the FSMs and HSMs.
///
/// \include qepn_qfsm.cpp
#define HSM_HANDLED()         (HSM_RET_HANDLED)

/// \brief Value returned by a state-handler function when it takes a
/// regular state transition.
#define HSM_RET_TRAN          ((HSMState)2)

/// \brief Designates a target for an initial or regular transition.
/// HSM_TRAN() can be used both in the FSMs and HSMs.
///
/// \include qepn_qtran.cpp
//lint -e960 -e1924 ignore MISRA Rule 42 (comma operator) and C-style cast
#define HSM_TRAN(target_)  \
    (me->m_state = (HSMStateHandler)(target_), HSM_RET_TRAN)

/// \brief Value returned by a state-handler function when it cannot
/// handle the event.
#define HSM_RET_SUPER         ((HSMState)3)

/// \brief Designates the superstate of a given state in an HSM.
///
/// \include qepn_Hsm.cpp
//lint -e960 -e1924 ignore MISRA Rule 42 (comma operator) and C-style cast
#define HSM_SUPER(super_)  \
    (me->m_state = (HSMStateHandler)(super_),  HSM_RET_SUPER)


//////////////////////////////////////////////////////////////////////////////
/// \brief QEP reserved signals.
enum HSMReservedSignals {
    HSM_ENTRY_SIG = 1,                             ///< signal for entry actions
    HSM_EXIT_SIG,                                   ///< signal for exit actions
    HSM_INIT_SIG,                     ///< signal for nested initial transitions
    HSM_UPDATE_SIG,			//for update actions
    HSM_USER_SIG                              ///< signal to offset user signals
};

extern HSMEvent const HSM_reservedEvt_[];

/// internal QEP constants
enum HMSConst {
    HSM_EMPTY_SIG_ = 0,                ///< empty signal for internal use only

    /// maximum depth of state nesting (including the top level), must be >= 3
    HSM_MAX_NEST_DEPTH_ = 7
};

/// helper macro to trigger internal event in an HSM
#define HSM_TRIG_(state_, sig_) \
    ((*(state_))(this, &HSM_reservedEvt_[sig_]))

/// helper macro to trigger entry action in an HSM
#define HSM_EXIT_(state_) \
    if (HSM_TRIG_(state_, HSM_EXIT_SIG) == HSM_RET_HANDLED) { \
    }

/// helper macro to trigger exit action in an HSM
#define HSM_ENTER_(state_) \
    if (HSM_TRIG_(state_, HSM_ENTRY_SIG) == HSM_RET_HANDLED) { \
    }

/// helper macro to init HSM state
#define HSM_INIT_(state_)  \
    { this->m_state = (HSMStateHandler)(state_); this->hsm_init(); }

/// helper macro to transform HSM state
#define HSM_TRANSFORM(state_)  \
    { this->hsm_transform((state_)); }


#endif                                                                // HSM_h
